
#include "channel.h"

#include <stdio.h>
#include <sys/shm.h>
#include <errno.h>
#include <string.h>
#include <pthread.h>


// base shm channel class
struct channel_t
{
	union {
		struct {
			int type; // common to any kind of channel

			key_t key;
			int id;

			key_t altKey; // when set, receiver is receiving on this channel thru an Alternative

			pthread_mutex_t mutex;
			pthread_cond_t cond;
		};
		char null[1024];
	};

};


struct channel_t *LCreattach( struct channel_t *ch );

struct channel_t *LCattach( key_t key )
{
    /* we have to acquire the shared segmet twice: the first one to get the channel * struct.
    Then we know the properties of the channel (type, size,...) and we can attach it
    properly*/
	struct channel_t *tmpCh, *ch;
	int type;

	int id = shmget( key, sizeof(*ch), 0700 );
	if( id == -1 ) {
		printf( "[GENERIC] sender::shmget(): %s\n", strerror(errno) );
		return NULL;
	}

	tmpCh = shmat( id, 0, 0 );
	if( ! tmpCh ) {
		printf( "[GENERIC] sender::shmat(): %s\n", strerror(errno) );
		return NULL;
	}

	type = tmpCh->type;

	// getting it, using the apposite function
	ch = LCreattach( tmpCh );

	// freeing channel
	shmdt( tmpCh );

	return ch;
}

// common functions
inline int __LClockChannel( struct channel_t *ch ) {
	return pthread_mutex_lock( & ch->mutex );
}
inline int __LCunlockChannel( struct channel_t *ch ) {
	return pthread_mutex_unlock( & ch->mutex );
}
inline int __LCwaitOnChannel( struct channel_t *ch ) {
	return pthread_cond_wait( & ch->cond, & ch->mutex );
}
inline int __LCwakeUpChannel( struct channel_t *ch ) {
	return pthread_cond_signal( & ch->cond );
}

inline void __LCsetAltKey( struct channel_t *ch, key_t altKey )
{
	ch->altKey = altKey;
}
// end common functions


struct channel_t *LCreattach_ss( struct channel_t *ch );
struct channel_t *LCreattach_as( struct channel_t *ch );
struct channel_t *LCreattach( struct channel_t *ch )
{
	switch( ch->type ) {
		case SYNCHRONOUS_SYMMETRIC:
			return LCreattach_ss( ch );
		case ASYNCHRONOUS_SYMMETRIC:
			return LCreattach_as( ch );
	}

	printf( "Error: unknown channel type %d!\n", ch->type );
	return  0;
}

void LCdestroy_ss( struct channel_t *ch );
void LCdestroy_as( struct channel_t *ch );
void LCdestroy( struct channel_t *ch ) //eliminabile
{
	switch( ch->type ) {
		case SYNCHRONOUS_SYMMETRIC:
			return LCdestroy_ss( ch );
		case ASYNCHRONOUS_SYMMETRIC:
			return LCdestroy_as( ch );
	}

	printf( "Error: unknown channel type %d!\n", ch->type );
	return ;
}

void LCdetatch_ss( struct channel_t *ch );
void LCdetatch_as( struct channel_t *ch );
void LCdetatch( struct channel_t *ch )//eliminabile
{
	switch( ch->type ) {
		case SYNCHRONOUS_SYMMETRIC:
			return LCdetatch_ss( ch );
		case ASYNCHRONOUS_SYMMETRIC:
			return LCdetatch_as( ch );
	}

	printf( "Error: unknown channel type %d!\n", ch->type );
	return ;
}

void LCsend_ss( struct channel_t *ch, char *msg );
void LCsend_as( struct channel_t *ch, char *msg );
void LCsend( struct channel_t *ch, char *msg ) //eliminabile
{
	switch( ch->type ) {
		case SYNCHRONOUS_SYMMETRIC:
			return LCsend_ss( ch, msg );
		case ASYNCHRONOUS_SYMMETRIC:
			return LCsend_as( ch, msg );
	}

	printf( "Error: unknown channel type %d!\n", ch->type );
	return ;
}

char *LCreceive_ss( struct channel_t *ch );
char *LCreceive_as( struct channel_t *ch );
char *LCreceive( struct channel_t *ch ) //eliminabile
{
	switch( ch->type ) {
		case SYNCHRONOUS_SYMMETRIC:
			return LCreceive_ss( ch );
		case ASYNCHRONOUS_SYMMETRIC:
			return LCreceive_as( ch );
	}

	printf( "Error: unknown channel type %d!\n", ch->type );
	return  0;
}

size_t LCgetChannelTypeSize_ss( struct channel_t *ch );
size_t LCgetChannelTypeSize_as( struct channel_t *ch );
size_t LCgetChannelTypeSize( struct channel_t *ch ) //eliminabile
{
	switch( ch->type ) {
		case SYNCHRONOUS_SYMMETRIC:
			return LCgetChannelTypeSize_ss( ch );
		case ASYNCHRONOUS_SYMMETRIC:
			return LCgetChannelTypeSize_as( ch );
	}

	printf( "Error: unknown channel type %d!\n", ch->type );
	return  0;
}

bool LCreadyToReceive_ss( struct channel_t *ch );
bool LCreadyToReceive_as( struct channel_t *ch );
bool LCreadyToReceive( struct channel_t *ch ) //eliminabile
{
	switch( ch->type ) {
		case SYNCHRONOUS_SYMMETRIC:
			return LCreadyToReceive_ss( ch );
		case ASYNCHRONOUS_SYMMETRIC:
			return LCreadyToReceive_as( ch );
	}

	printf( "Error: unknown channel type %d!\n", ch->type );
	return  0;
}

bool LCreadyToSend_ss( struct channel_t *ch );
bool LCreadyToSend_as( struct channel_t *ch );
bool LCreadyToSend( struct channel_t *ch ) //elimin
{
	switch( ch->type ) {
		case SYNCHRONOUS_SYMMETRIC:
			return LCreadyToSend_ss( ch );
		case ASYNCHRONOUS_SYMMETRIC:
			return LCreadyToSend_as( ch );
	}

	printf( "Error: unknown channel type %d!\n", ch->type );
	return  0;
}

void printCH_ss( struct channel_t *ch );
void printCH_as( struct channel_t *ch );
void printCH( struct channel_t *ch )//elimin
{
	switch( ch->type ) {
		case SYNCHRONOUS_SYMMETRIC:
			return printCH_ss( ch );
		case ASYNCHRONOUS_SYMMETRIC:
			return printCH_as( ch );
	}

	printf( "Error: unknown channel type %d!\n", ch->type );
	return ;
}


